﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Windows;
using System.Windows.Input;
using System.Collections.Specialized;
using System.Windows.Data;


namespace GMUtilitiesDotNet.Gestures
{
    /// <summary>
    /// This class defines attached property for connecting gesture classes with commands.
    /// Gesture class receives mouse and keyboard input from UIElement and if events occur in
    /// certain order, corresponding command is executed.
    /// This class is modified version of EventCommander (Cinch framework class for connecting
    /// events to commands)
    /// <see cref="http://www.codeproject.com/KB/WPF/CinchII.aspx"/>
    /// </summary>
    public static class InputGesturesCommandMapper
    {
        // Make it internal so WPF ignores the property and always uses the 
        //public getter/setter.  This is per John Gossman blog post - 07/2008.
        // See: http://blogs.msdn.com/johngossman/archive/2008/07/28/how-to-initialize-an-attached-dependencyproperty-of-type-collection.aspx
        // "...hide the DP from the XAML parser, which can be done by using a different name for the 
        // registered DP (and making it internal is a good idea), and defining the attached property
        // by using the static getter and setter.  So if the DP is called InternalVisualStateGroups
        // and the getter and setter are for VisualStateGroups, the parser will call the static property."
        internal static readonly DependencyProperty MappingsProperty =
            DependencyProperty.RegisterAttached( "InternalMappings",
                            typeof( GestureCommandsCollection ), typeof( InputGesturesCommandMapper ),
                            new UIPropertyMetadata( null, OnMappingsChanged ) );

        internal static GestureCommandsCollection InternalGetMappingCollection( DependencyObject obj )
        {
            var map = obj.GetValue( MappingsProperty ) as GestureCommandsCollection;
            if( map == null )
            {
                map = new GestureCommandsCollection();
                SetMappings( obj, map );
            }
            return map;
        }

        public static GestureCommandsCollection GetMappings( DependencyObject obj )
        {
            return InternalGetMappingCollection( obj );
        }

        public static void SetMappings( DependencyObject obj, GestureCommandsCollection value )
        {
            obj.SetValue( MappingsProperty, value );
        }

        /// <summary>
        /// Called when attached property changes.
        /// </summary>
        /// <param name="target">Dependency object containing attached property</param>
        /// <param name="e">Event arguments</param>
        private static void OnMappingsChanged( DependencyObject target,
                                               DependencyPropertyChangedEventArgs e )
        {
            UIElement uiElement = target as UIElement;

            // dependency object has to be UiElement so GestureCommandsCollection can subscribe to it
            if (uiElement == null)
            {
                string errorMsg = "Object implementing GestureCommandsCollection attached property has to be UIElement.\n";
                errorMsg += "Object = " + target.ToString();
                throw new ArgumentException(errorMsg);
            }
                 
            if( e.OldValue != null )
            {
                GestureCommandsCollection gcc = e.OldValue as GestureCommandsCollection;
                if( gcc != null )
                {
                    gcc.Unsubscribe(uiElement);
                }
            }

            if( e.NewValue != null )
            {
                GestureCommandsCollection gcc = e.NewValue as GestureCommandsCollection;
                if( gcc != null )
                {
                    gcc.Subscribe(uiElement);
                }
            }
        }
    }
}
